#include<iostream>
#include<unistd.h>
#include<fcntl.h>
#include<cstdio>
#include<cstring>
#include<functional>
#include<vector>

using namespace std;

using func_t=std::function<void(void)>;
std::vector<func_t> funcs;//容器中存储着各种方法

void PrintLog()
{
    std::cout << "这个是一个日志例程" << std::endl;
}
void OperMysql()
{
    std::cout << "这个是一个操作数据库的例程" << std::endl;
}
void CheckNet()
{
    std::cout << "这个是一个检测网络状态的例程" << std::endl;
}

//如果一个线程想让另一个线程派发任务
void LoadTask()
{
    funcs.push_back(PrintLog);
    funcs.push_back(OperMysql);
    funcs.push_back(CheckNet);
}

void HandlerALLTask()
{
    for(const auto &func : funcs) func();
}

void SetNonBlock(int fd)//将文件描述符fd设置成非阻塞
{
    int fl=fcntl(fd,F_GETFL);
    if(fl<0)
    {
        std::cerr<<"error string"<<strerror(errno)<<"errno code:"<<errno<<endl;
        return ;
    }
    fcntl(fd,F_SETFL,fl|O_NONBLOCK);
    //使用F_GETFL将当前的文件描述符的属性取出来(这是一个位图).
    //然后再使用F_SETFL将文件描述符设置回去. 设置回去的同时, 加上一个O_NONBLOCK参数
}

int main()
{
    char buffer[1024];
    SetNonBlock(0);//将文件描述符0设置为非阻塞
    LoadTask();//加载任务
    while(true)
    {
        printf(">>>>>");
        fflush(stdout);//刷新缓冲区
        ssize_t n=read(0,buffer,sizeof(buffer)-1);//返回从键盘上读取到的字节数
        if(n>0)
        {
            buffer[n-1]=0;//这里是因为read函数不会为buffer中内容增加null终止符
            //因此需要将字符串的最后一个字符设置为null终止符，即ASCII码值0，使得字符串能被printf或cout识别
            cout<<"#"<<buffer<<endl;
        }
        else if(n==0)//代表读到了文件结尾，即用户停止输入
        {
            std::cout<<"end file"<<std::endl;
            break;
        }
        else
        {
            if(errno==EAGAIN || errno==EWOULDBLOCK)
            {
                //底层数据没有准备好（也就是键盘没有输入）
                HandlerALLTask();//没有输入时可以执行其他任务
                sleep(1);
                std::cout<<"datan not ready"<<std::endl;
                continue;
            }
            else if(errno==EINTR)
            {
                //IO信号中断，需要重新读取
            }
            else//真正出现read错误
            {
                std::cerr<<"read error"<<"error string:"<<strerror(errno)<<"errno code"<<errno<<std::endl;
                break;
            }
        }
        sleep(1);
    }

    return 0;
}